package com.jg.visitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jg.visitor.GlobalConst;
import com.jg.visitor.common.bean.PageDTO;
import com.jg.visitor.common.bean.WechatInfoBean;
import com.jg.visitor.common.utils.*;
import com.jg.visitor.config.exception.BaseException;
import com.jg.visitor.controller.dto.*;
import com.jg.visitor.controller.enums.ProcessEnum;
import com.jg.visitor.controller.enums.VisitorApplyRecordStatusEnum;
import com.jg.visitor.controller.enums.VisitorRecordOperationEnum;
import com.jg.visitor.controller.vo.AdminRecordQueryVO;
import com.jg.visitor.controller.vo.ApproverApproveVO;
import com.jg.visitor.controller.vo.ApproverQueryVO;
import com.jg.visitor.controller.vo.CarInformationVO;
import com.jg.visitor.domain.*;
import com.jg.visitor.kafka.producer.MsgSendService;
import com.jg.visitor.mapper.VisitorApplyRecordMapper;
import com.jg.visitor.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ApproverServiceImpl implements ApproverService {

    @Resource
    private VisitorApplyRecordService visitorApplyRecordService;
    @Resource
    private VisitorInfoService visitorInfoService;
    @Resource
    private HealthInfoService healthInfoService;
    @Resource
    private FileUploadRecordService fileUploadRecordService;
    @Resource
    private OperationRecordService operationRecordService;
    @Resource
    private SignRecordService signRecordService;
    @Resource
    private JsonService jsonService;
    @Resource
    private VisitorApplyRecordMapper visitorApplyRecordMapper;
    @Resource
    private MsgSendService msgSendService;
    @Resource
    private UserService userService;

    @Override
    public PageDTO<ApproverApproveRecordDTO> selectWaitSelfApproveRecord(AdminRecordQueryVO approverQueryVO) {
        //默认查询全部状态
        if(approverQueryVO.getSearchType() == null){
            approverQueryVO.setSearchType(ApproverQueryVO.StatusEnum.ALL.getStatus());
        }

        UserDTO loginUser = LoginHelper.getLoginUser();
        if(null == loginUser){
            throw new BaseException(-1,"后台人员登录信息异常！");
        }

        PageDTO<ApproverApproveRecordDTO> pageDTO = new PageDTO<>();
        pageDTO.setPage(approverQueryVO.getPage());
        pageDTO.setPageSize(approverQueryVO.getPageSize());

        List<VisitorApplyRecord> dataList;

        //注释  通过mapper查询 sql直接分页，不然只能全部查询出来手动分页 改死我了  sql里面其实可以直接查询处visitor信息了，不用后面批量查询再设置，
        // 但是不想改，后序性能问题再优化把
//        {
//            Integer userType = loginUser.getType();
//            QueryWrapper<VisitorApplyRecord> queryWrapper = new QueryWrapper<VisitorApplyRecord>()
//                    .last(" order by convert(datetime,gmt_modified) desc");
//
//            //非管理员（被访者，安全员查询时排除黑名单）
//            if(!GlobalConst.USER_TYPE_ADMIN.equals(userType)){
//                queryWrapper.notExists("select 1 from blacklist bl where bl.visitor_id = visitor_apply_record.visitor_info_id");
//            }
//
//            //查询用户类型 被访者只能查询被访人是自己的记录，安全员，超级管理员能查询所有记录
//            if(GlobalConst.USER_TYPE_INTERVIEWEE.equals(userType)){
//                queryWrapper.eq("contacts_phone",loginUser.getUsername());
//            }
//
//            //被访者
//            if(!StringUtils.isEmpty(approverQueryVO.getContacts())){
//                queryWrapper.like("contacts",approverQueryVO.getContacts());
//            }
//
//            //查询待审核
//            if(ApproverQueryVO.StatusEnum.WAIT_APPROVE.getStatus().equals(approverQueryVO.getSearchType())){
//                //被访者查询待审核，只能查询待被访者审核状态的数据
//                if(GlobalConst.USER_TYPE_INTERVIEWEE.equals(userType)){
//                    queryWrapper.eq("status", VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode());
//                }
//                //安全员查询待审核，既可以查询待被访者审核且被访者是自己的状态的数据，又可以查询待安全员审核状态的全部数据
//                else if(GlobalConst.USER_TYPE_SAFETY_OFFICER.equals(userType)){
//                    queryWrapper
//                            .eq("status", VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode())
//                            .or(a -> a
//                                    .eq("status",VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode())
//                                    .eq("contacts_phone",loginUser.getUsername()));
//                }
//                //管理员查询待审核，申请单状态为待被访者审核或者待安全员审核都算
//                else{
//                    queryWrapper
//                            .and(a -> a
//                                    .eq("status",VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode())
//                                    .or()
//                                    .eq("status",VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode()));
//                }
//
//            }
//            //查询已审核
//            else if(ApproverQueryVO.StatusEnum.APPROVED.getStatus().equals(approverQueryVO.getSearchType())){
//                //被访者查询，则筛选id为操作记录表里面操作类型为被访者审批的申请单
//                if(GlobalConst.USER_TYPE_INTERVIEWEE.equals(userType)){
//                    queryWrapper.apply(" id in (select apply_record_id from operation_record where operator_id = "
//                            + loginUser.getId()
//                            +  " and operation_type =  "
//                            + VisitorRecordOperationEnum.INTERVIEWEE_APPROVED.getOperationCode() + ")");
//                }
//                //安全员查询，则筛选id为操作记录表里面操作类型为安全员审批的申请单
//                else if(GlobalConst.USER_TYPE_SAFETY_OFFICER.equals(userType)){
//                    queryWrapper.apply(" id in (select apply_record_id from operation_record where operator_id = "
//                            + loginUser.getId()
//                            +  " and operation_type =  "
//                            + VisitorRecordOperationEnum.SAFER_APPROVED.getOperationCode() + ")");
//                }
//                //管理员查询已审核。暂时视作其他情况都算已审核
//                else{
//                    queryWrapper.notIn("status",
//                            Arrays.asList(VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode(),
//                                    VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode()));
//                }
//            }
//            //否则如果不是查询全部则抛出异常
//            else if(!ApproverQueryVO.StatusEnum.ALL.getStatus().equals(approverQueryVO.getSearchType())){
//                throw new BaseException(-1,"查询数据类型异常！");
//            }
//        }

        //检测分页

        if(!CheckParamUtils.isAnyParamNull(approverQueryVO.getPage(),approverQueryVO.getPageSize())){
            Page<VisitorApplyRecord> pageData = new Page<>(approverQueryVO.getPage(),approverQueryVO.getPageSize());
            dataList = visitorApplyRecordMapper.selectByCondition(pageData,loginUser,approverQueryVO);
            pageDTO.setTotal(pageData.getTotal());
        }
        else{
            dataList = visitorApplyRecordMapper.selectByCondition(loginUser,approverQueryVO);
            pageDTO.setTotal(dataList.size());
        }

        //没有数据直接返回
        if(CollectionUtils.isEmpty(dataList)){
            pageDTO.setData(new ArrayList<>());
            return pageDTO;
        }

        //查询每个单子的访客信息
//        List<Long> visitorIdList = dataList
//                .stream().map(VisitorApplyRecord::getVisitorInfoId).collect(Collectors.toList());
//        List<VisitorInfo> visitorInfoList = visitorInfoService.listByIds(visitorIdList);

        //查询每个单子的健康信息
        List<Long> healthIdList = dataList
                .stream().map(VisitorApplyRecord::getHealthInfoId).collect(Collectors.toList());
        List<HealthInfo> healthInfoList = healthInfoService.listByIds(healthIdList);

        //查询健康图片
        List<Long> imgIdList = healthInfoList
                .stream()
                .map(health -> Arrays
                        .asList(health.getHealthPictureId(), health.getTripPictureId(), health.getNucleicPictureId()))
                .flatMap(List::stream).collect(Collectors.toList());
        List<FileUploadRecord> fileUploadRecordList = CollectionUtils.isEmpty(imgIdList) ?
                new ArrayList<>() : fileUploadRecordService.listByIds(imgIdList);

        //查询这些单子的操作记录
        List<Long> visitorApplyRecordIdList = dataList
                .stream().map(VisitorApplyRecord::getId).collect(Collectors.toList());
        List<OperationRecord> operationRecordList = operationRecordService.list(
                new QueryWrapper<OperationRecord>().in("apply_record_id",visitorApplyRecordIdList));

        //查询进出记录
        List<SignRecord> allSignRecord = CollectionUtils.isEmpty(visitorApplyRecordIdList) ?
                new ArrayList<>() :
                signRecordService.list(new QueryWrapper<SignRecord>().in("visitor_apply_id",visitorApplyRecordIdList));

        //得到dto数据,返回
        List<ApproverApproveRecordDTO> approverApproveRecordDTOList = dataList
                .stream()
                .map(data -> {
                    ApproverApproveRecordDTO dto = new ApproverApproveRecordDTO();

                    //申请人
                    VisitorInfo visitor = jsonService.jsonToObject(data.getVisitorInfoJson(),VisitorInfo.class);
                    VisitorInfoDTO visitorInfoDTO = new VisitorInfoDTO();
                    BeanUtils.copyProperties(visitor, visitorInfoDTO);
                    if(!StringUtils.isEmpty(visitor.getVehicleInf())){
                        CarInformationVO informationVO = jsonService
                                .jsonToObject(visitor.getVehicleInf(), CarInformationVO.class);
                        visitorInfoDTO.setPlateNumber(informationVO.getPlateNumber());
                        visitorInfoDTO.setVehicleBrand(informationVO.getBrand());
                    }
                    dto.setVisitorInfoDTO(visitorInfoDTO);

                    //申请记录
                    VisitorApplyRecordDTO visitorApplyRecordDTO = visitorApplyRecordService
                            .getVisitorApplyRecordDTOByVisitorApplyRecord(data, healthInfoList, fileUploadRecordList,
                                    operationRecordList,allSignRecord);
                    dto.setVisitorApplyRecordDTO(visitorApplyRecordDTO);

                    //操作记录
                    List<OperationRecord> operationList = operationRecordList
                            .stream()
                            .filter(operationRecord -> operationRecord.getApplyRecordId().equals(data.getId()))
                            .collect(Collectors.toList());
                    List<OperationDTO> operationDTOList = operationList.stream().map(operationRecord -> {
                        OperationDTO operationDTO = new OperationDTO();
                        BeanUtils.copyProperties(operationRecord, operationDTO);
                        return operationDTO;
                    }).collect(Collectors.toList());
                    dto.setOperationDTO(operationDTOList);

                    return dto;
                })
                .collect(Collectors.toList());
        pageDTO.setData(approverApproveRecordDTOList);

        return pageDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void operateOrder(ApproverApproveVO approverApproveVO) {
        UserDTO loginUser = LoginHelper.getLoginUser();

        if(null == loginUser){
            throw new BaseException(-1,"审批人信息异常！");
        }

        //拿到原始申请记录
        VisitorApplyRecord visitorApplyRecord = visitorApplyRecordService.getById(approverApproveVO.getVisitorApplyRecordId());

        //当前用户是否能修改此单子状态
        checkOperateFlag(loginUser,visitorApplyRecord);

        //更新申请记录状态
        updateRecordStatusAndInsertOperationRecord(approverApproveVO,loginUser,visitorApplyRecord);

    }

    private void checkOperateFlag(UserDTO loginUser,VisitorApplyRecord visitorApplyRecord){
        if(null == visitorApplyRecord){
            throw new BaseException(-1,"没有找到此申请记录！");
        }

        boolean canOperate = true;
        //有可能安全员同时在审批，所以审批时根据用户类型判断状态，不符合要求则不允许操作
        if(GlobalConst.USER_TYPE_INTERVIEWEE.equals(loginUser.getType())){
            if (!VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode().equals(visitorApplyRecord.getStatus())){
                canOperate = false;
            }
        }
        else if(GlobalConst.USER_TYPE_SAFETY_OFFICER.equals(loginUser.getType())){
            //如果当前用户是安全员,申请单不是待被访者审批以及待安全员审批则不能操作
            if(!VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode().equals(visitorApplyRecord.getStatus()) &&
                    !VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode().equals(visitorApplyRecord.getStatus())){
                canOperate = false;
            }
        }
        else{
            throw new BaseException(-1,"当前用户不允许修改此申请记录状态！");
        }

        if(!canOperate){
            throw new BaseException(-1,"申请记录状态已被其他人更新,请刷新！");
        }
    }

    private void updateRecordStatusAndInsertOperationRecord(ApproverApproveVO approverApproveVO,
                                                            UserDTO loginUser,
                                                            VisitorApplyRecord record){
        //操作记录
        OperationRecord operationRecord = new OperationRecord();
        operationRecord.setApplyRecordId(record.getId());
        operationRecord.setOldStatus(record.getStatus());
        operationRecord.setOperatorTime(DateTimeUtil.getTimeNow());
        operationRecord.setOperatorId(loginUser.getId());
        operationRecord.setOperatorName(loginUser.getNickname());
        operationRecord.setApplyFlag(approverApproveVO.getApplyResult());
        operationRecord.setAdminFlag(GlobalConst.ADMIN_FLAG_TRUE);
        operationRecord.setRemark(approverApproveVO.getRemark());

        //访客信息
        VisitorInfo visitorInfo = visitorInfoService.getById(record.getVisitorInfoId());


        //被访者
        if(GlobalConst.USER_TYPE_INTERVIEWEE.equals(loginUser.getType())){
            if(GlobalConst.APPLY.equals(approverApproveVO.getApplyResult())){
                record.setStatus(VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode());
                //被访者通过 通知所有安全员消息
                sendPaasWechatMsgToAllSafer(record.getApplyOrderNum(),visitorInfo.getUsername());
            }
            else if(GlobalConst.REFUSE.equals(approverApproveVO.getApplyResult())){
                record.setStatus(VisitorApplyRecordStatusEnum.RESPONDENTS_REFUSE.getStatusCode());
                //被访者拒绝，推送消息
                sendKafkaMsg(record.getApplyOrderNum(),visitorInfo.getUsername(),visitorInfo.getOpenId(), ProcessEnum.REFUSED);
            }
            else{
                throw new BaseException(-1,"审批状态异常！");
            }
            //被访者审批
            operationRecord.setOperationType(VisitorRecordOperationEnum.INTERVIEWEE_APPROVED.getOperationCode());
        }
        else if(GlobalConst.USER_TYPE_SAFETY_OFFICER.equals(loginUser.getType())){
            if(GlobalConst.APPLY.equals(approverApproveVO.getApplyResult())){
                //如果原来的状态是待被访者审批，则更新状态到待安全员审批,否则更新到审批通过
                if(VisitorApplyRecordStatusEnum.WAIT_RESPONDENTS_APPROVE.getStatusCode().equals(record.getStatus())){
                    record.setStatus(VisitorApplyRecordStatusEnum.WAIT_SAFER_APPROVE.getStatusCode());
                    //安全员以被访者角色进行被访者审批
                    operationRecord.setOperationType(VisitorRecordOperationEnum.INTERVIEWEE_APPROVED.getOperationCode());

                    //被访者通过 通知所有安全员消息
                    sendPaasWechatMsgToAllSafer(record.getApplyOrderNum(),visitorInfo.getUsername());
                }
                else{
                    record.setStatus(VisitorApplyRecordStatusEnum.PASS.getStatusCode());
                    //安全员通过，推送消息
                    sendKafkaMsg(record.getApplyOrderNum(),visitorInfo.getUsername(),visitorInfo.getOpenId(), ProcessEnum.APPROVED);
                    //安全员审批
                    operationRecord.setOperationType(VisitorRecordOperationEnum.SAFER_APPROVED.getOperationCode());
                }
            }
            else if(GlobalConst.REFUSE.equals(approverApproveVO.getApplyResult())){
                record.setStatus(VisitorApplyRecordStatusEnum.SAFER_REFUSE.getStatusCode());
                //安全员拒绝，推送消息
                sendKafkaMsg(record.getApplyOrderNum(),visitorInfo.getUsername(),visitorInfo.getOpenId(), ProcessEnum.REFUSED);
                //安全员审批
                operationRecord.setOperationType(VisitorRecordOperationEnum.SAFER_APPROVED.getOperationCode());
            }
            else{
                throw new BaseException(-1,"审批状态异常！");
            }
        }
        else{
            throw new BaseException(-1,"用户类型信息异常！");
        }

        //新状态
        operationRecord.setNewStatus(record.getStatus());

        //更新申请记录状态
        record.setGmtModified(DateTimeUtil.getTimeNow());
        record.updateById();

        //插入操作记录
        operationRecord.insert();
    }

    public void sendPaasWechatMsgToAllSafer(String orderNum,String visitorName){
        List<String> saferOpenIdList = userService.list(new QueryWrapper<User>()
                .eq("type", GlobalConst.USER_TYPE_SAFETY_OFFICER)
                .isNotNull("open_id")
                .select("open_id"))
                .stream()
                .map(User::getOpenId)
                .collect(Collectors.toList());
        saferOpenIdList
                .forEach(openId -> sendKafkaMsg(orderNum,visitorName,openId, ProcessEnum.APPROVED));
    }

    public void sendKafkaMsg(String applyOrderNum,
                             String customerName,
                             String openId,
                             ProcessEnum processEnum){
        WechatInfoBean wechatInfoBean = new WechatInfoBean();
        wechatInfoBean.setApplyOrderNum(applyOrderNum);
        wechatInfoBean.setUsername(customerName);
        wechatInfoBean.setProcessEnum(processEnum);
        wechatInfoBean.setOpenId(openId);

        msgSendService.sendWechatMsg(wechatInfoBean);
    }
}
